const AxiosDefault = require("axios").default;
const util = require("util");
const randomColor = require("random-color");

class GiteeApiOnRepo {
  /**
   * 
   * @param {String} token - must be a valid token
   * @param {String} owner
   * @param {String} repo
   */
  constructor(token, owner, repo) {
    this._token = token;
    this.owner = owner;
    this.repo = repo;
    this.axios = AxiosDefault.create({
      headers: {
        Authorization: `token ${token}`,
        "Content-Type": "application/json",
        "Accept": "application/json",
        "User-Agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"
      }
    });
  }

  /**
   * @description 新建的issue的状态都是open
   * @param {String} title 
   * @param {String} body 
   * @param {Number} milestone_number  0表示没有,正常的milestone是从1开始计数的
   * @param {String[]} labels 
   * @returns {Promise<{ok:Boolean,msg:String,issue:{number:String,api_url:String,labels:String[],milestone:String|null}}>}
   */
  createIssue(title, body, milestone_number = 0, labels = []) {
    return new Promise(async resolve => {
      this.axios.post(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues#创建issue(带milestone)`, {
        title: title,
        body: body,
        milestone: milestone_number,
        labels: labels
      }, {
        validateStatus: s => s == 201
      }).then(axresp => {
        let d = axresp.data;
        resolve({
          ok: true,
          msg: "ok",
          issue: {
            number: d['number'],
            api_url: d['url'],
            labels: d['labels'].map(l => l['name']),
            milestone: d['milestone'] ? d['milestone']['title'] : null
          }
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }


  /**
   * @description 当用多个label去搜索的时候,得到的是分别单个label搜索时的并集!
   * @param {Number} page
   * @param {Number} per_page
   * @param {String[]} labels 
   * @returns {Promise<{ok:Boolean,msg:String,issues:Array<{number:String,api_url:String,labels:String[],milestone:String|null}>}>}
   */
  findIssueByLabels(labels = [], page = 1, per_page = 20) {
    return new Promise(resolve => {
      this.axios.get(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues?page=${page}&per_page=${per_page}${labels.length?"&labels="+labels.join(","):""}`, {
        validateStatus: s => s == 200
      }).then(axresp => {
        let d = axresp.data;
        resolve({
          ok: true,
          msg: "ok",
          issues: d.map(i => {
            return {
              number: i['number'],
              api_url: i['url'],
              labels: i['labels'].map(l => l['name']),
              milestone: i['milestone'] ? i['milestone']['title'] : null
            }
          })
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })

  }


  /**
   * 
   * @param {String|"none"|"*"} milestone_title
   * @param {"open"|"closed"|"all"} state 
   * @param {Number} page 
   * @param {Number} per_page 
   * @returns {Promise<{ok:Boolean,msg:String,issues:Array<{number:String,api_url:String,labels:String[],milestone:String|null}>}>}
   */
  findIssueByStateAndMileStone(milestone_title = "*", state = "open", page = 1, per_page = 20) {
    return new Promise(resolve => {
      this.axios.get(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues?page=${page}&per_page=${per_page}&state=${state}&milestone=${milestone_title}`, {
        validateStatus: s => s == 200
      }).then(axresp => {
        let d = axresp.data;
        resolve({
          ok: true,
          msg: "ok",
          issues: d.map(i => {
            return {
              number: i['number'],
              api_url: i['url'],
              labels: i['labels'].map(l => l['name']),
              milestone: i['milestone'] ? i['milestone']['title'] : null
            }
          })
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

  /**
   * 
   * @param {String} number - issue number
   * @returns {Promise<{ok:Boolean,msg:String,issue:{body:String,state:String,title:String,number:String,api_url:String,labels:String[],milestone:String|null}}>}
   */
  queryIssueByNumber(number) {
    return new Promise(resolve => {
      this.axios.get(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues/${number}`, {
        validateStatus: s => s == 200
      }).then(axresp => {
        let d = axresp.data;
        resolve({
          ok: true,
          msg: "ok",
          issue: {
            number: d['number'],
            body: d['body'],
            title: d['title'],
            state: d['state'],
            api_url: d['url'],
            labels: d['labels'].map(l => l['name']),
            milestone: d['milestone'] ? d['milestone']['title'] : null
          }
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

  /**
   * @description milestone_number必须是已经存在的合法的number,否则即使返回200,其实是没有变化的;在本API中要求用户自己保证这个前提条件
   * @param {String} issue_number 
   * @param {Number} milestone_number
   * @returns {Promise<{ok:Boolean,msg:String}>} 
   */
  changeIssueMilestone(issue_number, milestone_number) {
    return new Promise(resolve => {
      this.axios.patch(`https://gitee.com/api/v5/repos/${this.owner}/issues/${issue_number}#修改issue内容`, {
        milestone: milestone_number
      }, {
        validateStatus: s => s == 200
      }).then(axresp => {
        resolve({
          ok: true,
          msg: "ok"
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

  /**
   * @description 在原有的基础上添加labels ; patch里的label必须是已经出现过的label,否则会失效,因此需要手动先创建label
   * @param {String} issue_number 
   * @param {String[]} labels 
   * @returns {Promise<{ok:Boolean,msg:String}>}
   */
  addLabelsToIssue(issue_number, labels = []) {
    return new Promise(async resolve => {
      let o_creates = await Promise.all(labels.map(l => this.createLabel(l)))
      if (o_creates.findIndex(o => !o.ok) != -1) {
        return resolve({
          ok: false,
          msg: `Some labels failed to create :${o_creates.filter(o=>!o.ok).map(o=>o.msg).join("|")}`
        })
      }
      let o_query = await this.queryIssueByNumber(issue_number);
      if (!o_query.ok) {
        return resolve({
          ok: false,
          msg: `failed to query issue[${issue_number}]:${o_query.msg}`
        })
      }
      this.axios.patch(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues/${issue_number}`, {
        labels: o_query.issue.labels.concat(labels)
      }, {
        validateStatus: s => s == 200
      }).then(axresp => {
        resolve({
          ok: true,
          msg: "ok"
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

  /**
   * @description 在本API中,label已经存在也算是成功了!
   * @param {String} name 
   * @param {String} color for example "FF0080" 
   * @returns {Promise<{ok:Boolean,msg:String}>}
   */
  createLabel(name, color = "ff0080") {
    return new Promise(resolve => {
      this.axios.post(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/labels`, {
        name: name,
        color: color
      }, {
        validateStatus: s => s == 201 || s == 409
      }).then(axresp => {
        if (axresp.status == 201) {
          resolve({
            ok: true,
            msg: "201 created"
          })
        } else {
          resolve({
            ok: true,
            msg: "Label already exists"
          })
        }
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

  /**
   * 
   * @param {String} name 
   * @returns {Promise<{ok:Boolean,msg:String,exist:Boolean}>}
   */
  checkLabelExist(name = '404') {
    return new Promise(resolve => {
      this.axios.get(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/labels/${name}`, {
        validateStatus: s == 404 || s == 200
      }).then(axresp => {
        resolve({
          ok: true,
          msg: "ok",
          exist: axresp.status == 200
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })

  }

  /**
   * 
   * @param {String} issue_number 
   * @param {String} comment_text 
   * @returns {Promise<{ok:Boolean,msg:String}>}
   */
  addCommentToIssue(issue_number, comment_text) {
    return new Promise(resolve => {
      this.axios.post(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues/${issue_number}/comments`, {
        body: comment_text
      }, {
        validateStatus: s => s == 201
      }).then($ => {
        resolve({
          ok: true,
          msg: "ok"
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }


  /**
   * 
   * @param {String} issue_number 
   * @return {Promise<{ok:Boolean,msg:String}>}
   */
  closeIssue(issue_number) {
    return new Promise(resolve => {
      this.axios.patch(`https://gitee.com/api/v5/repos/${this.owner}/${this.repo}/issues/${issue_number}`, {
        state: "closed"
      }, {
        validateStatus: s => s == 200
      }).then(axresp => {
        resolve({
          ok: true,
          msg: "ok"
        })
      }).catch(axerr => {
        if (axerr.response) {
          return resolve({
            ok: false,
            msg: `HTTP ${axerr.response.status + axerr.response.statusText};${util.inspect(axerr.response.data)}`
          })
        } else {
          return resolve({
            ok: false,
            msg: axerr.message ? axerr.message : util.inspect(axerr)
          })
        }
      })
    })
  }

}



module.exports = {
  GiteeApiOnRepo: GiteeApiOnRepo
}